package jnpf.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jnpf.base.ActionResult;
import jnpf.common.enums.AiReqUrlEnum;
import jnpf.entity.ExternalLogin;
import jnpf.mapper.ExternalLoginMapper;
import jnpf.model.external.*;
import jnpf.service.ExternalLoginService;
import jnpf.util.JsonUtil;
import jnpf.util.RSAEncryptUtil;
import jnpf.util.RandomUtil;
import jnpf.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.Date;
import java.util.List;

@Service
@Slf4j
public class ExternalLoginServiceImpl extends ServiceImpl<ExternalLoginMapper, ExternalLogin> implements ExternalLoginService {
    @Value("${login.dify.url:}")
    private String difyUrl;

    @Value("${login.dify.name:}")
    private String difyName;

    @Value("${login.dify.password:}")
    private String difyPassword;

    @Value("${login.rag.url:}")
    private String ragUrl;

    @Value("${login.rag.name:}")
    private String ragName;

    @Value("${login.rag.password:}")
    private String ragPassword;

    @Autowired
    private Environment environment;


    @Override
    public ExternalLogin getByUsername(String username) {
        return lambdaQuery().eq(ExternalLogin::getUsername, username).one();
    }

    @Override

    public ActionResult apiLogin(LoginReq request)  {
        String url;
        String username;
        String password;
        String platform = request.getPlatform();

        // 根据平台选择登录方式
        if (platform.equals("2")) { // RAG平台
            url = ragUrl + "/v1/user/login";
            username = StringUtil.isNotEmpty(request.getEmail()) ? request.getEmail() : ragName;
            password = StringUtil.isNotEmpty(request.getPassword()) ? request.getPassword() : ragPassword;

            // 加密密码
            try {
                password = RSAEncryptUtil.encrypt(password);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }

            RestTemplate restTemplate = new RestTemplate();
            HttpHeaders headers = new HttpHeaders();
            headers.set("Accept", "*/*");
            headers.set("Content-Type", "application/json");

            // 创建请求实体
            LoginRagReq loginRagReq = new LoginRagReq();
            loginRagReq.setEmail(username);
            loginRagReq.setPassword(password);
            HttpEntity<LoginRagReq> entity = new HttpEntity<>(loginRagReq, headers);

            // 发送请求
            try {
                // 先尝试解析为成功响应

                ResponseEntity<LoginRagOkResp> response = restTemplate.postForEntity(url, entity, LoginRagOkResp.class);

                if (response.getStatusCode() == HttpStatus.OK) {
                    // 从响应头中获取 Authorization 字段
                    List<String> authorizationHeaders = response.getHeaders().get(HttpHeaders.AUTHORIZATION);
                    String token = null;
                    if (authorizationHeaders != null && !authorizationHeaders.isEmpty()) {
                        token = authorizationHeaders.get(0);
                        // 如果 token 以 "Bearer " 开头，去掉前缀
                        if (token.startsWith("Bearer ")) {
                            token = token.substring(7);
                        }
                    }
                    LoginRagOkResp body = response.getBody();

                    return handleLoginSuccess(username, password, "2", token);
                } else {
                    return ActionResult.fail("RAG登录失败: " + response.getBody());
                }
            } catch (Exception e) {
                // 捕获所有异常并尝试解析错误响应
                try {
                    LoginRagErrorResp errorResp = restTemplate.postForObject(url, entity, LoginRagErrorResp.class);
                    return ActionResult.fail("RAG登录失败: " + (errorResp != null ? errorResp.getMessage() : e.getMessage()));
                } catch (Exception ex) {
                    return ActionResult.fail("RAG登录失败: " + e.getMessage());
                }
            }
        } else if (platform.equals("1")) { // Dify平台
            url = difyUrl + "/console/api/login";
            username = StringUtil.isNotEmpty(request.getEmail()) ? request.getEmail() : difyName;
            password = StringUtil.isNotEmpty(request.getPassword()) ? request.getPassword() : difyPassword;

            RestTemplate restTemplate = new RestTemplate();
            HttpHeaders headers = new HttpHeaders();
            headers.set("Accept", "*/*");
            headers.set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6,zh-TW;q=0.5");
            headers.set("Content-Type", "application/json");

            // 创建请求实体
            LoginDifyReq loginDifyReq = new LoginDifyReq();
            loginDifyReq.setEmail(username);
            loginDifyReq.setPassword(password);
            HttpEntity<LoginDifyReq> entity = new HttpEntity<>(loginDifyReq, headers);

            try {
                ResponseEntity<LoginDifyOkResp> response = restTemplate.postForEntity(url, entity, LoginDifyOkResp.class);

                if (response.getStatusCode() == HttpStatus.OK) {
                    return handleLoginSuccess(username, password, "1", response.getBody().getData().getAccess_token());
                } else {
                    // 错误响应也使用LoginDifyErrorResp
                    return ActionResult.fail("Dify登录失败: " + response.getBody().getResult());
                }
            } catch (Exception e) {
                return ActionResult.fail("Dify登录请求发生异常: " + e.getMessage());
            }
        } else {
            return ActionResult.fail("不支持的平台类型");
        }
    }

    @Override
    public ActionResult createDifyAi(LoginReq request, DifyAiCreateReq difyAiCreateReq) throws Exception {
        // 验证请求参数
        if (difyAiCreateReq == null) {
            return ActionResult.fail("创建参数不能为空");
        }

        String username = StringUtil.isNotEmpty(request.getEmail()) ? request.getEmail() : difyName;
        String password = StringUtil.isNotEmpty(request.getPassword()) ? request.getPassword() : difyPassword;

        // 根据用户名获取token，如果不存在则创建新记录并获取token
        ExternalLogin externalLogin = this.getByUsername(username);
        if (externalLogin == null) {
            // 先创建用户记录
            externalLogin = new ExternalLogin();
            externalLogin.setId(RandomUtil.uuId());
            externalLogin.setUsername(username);
            externalLogin.setPassword(password);
            externalLogin.setPlatform("1");
            externalLogin.setCreatedAt(new Date());
            this.save(externalLogin);

            // 为新用户调用登录接口获取token
            LoginReq loginReq = new LoginReq();
            loginReq.setEmail(username);
            loginReq.setPassword(password);
            loginReq.setPlatform("1"); // Dify平台
            ActionResult loginResult = this.apiLogin(loginReq);

            if (loginResult.getCode() != 200) {
                return ActionResult.fail("新用户自动登录失败: " + loginResult.getMsg());
            }

            // 重新获取用户记录
            externalLogin = this.getByUsername(username);
        }

        if (StringUtil.isEmpty(externalLogin.getToken())) {
            return ActionResult.fail("请先登录Dify平台获取token");
        }
        String accessToken = externalLogin.getToken();

        // 使用枚举类中的URL常量
        String url = difyUrl + AiReqUrlEnum.CREATE_DIFY_AI.getUrl();

        // 设置请求头
        HttpHeaders headers = new HttpHeaders();
        headers.set("Accept", "*/*");
        headers.set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6,zh-TW;q=0.5");
        headers.set("Connection", "keep-alive");
        headers.set("Origin", difyUrl);
        headers.set("Referer", difyUrl + "/apps");
        headers.set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0");
        headers.set("Authorization", "Bearer " + accessToken);
        headers.set("Content-Type", "application/json");

        // 构建请求体
        String requestBody = JsonUtil.getObjectToString(difyAiCreateReq);

        // 创建请求实体并发送请求
        HttpEntity<String> entity = new HttpEntity<>(requestBody, headers);
        RestTemplate restTemplate = new RestTemplate();

        try {
            ResponseEntity<DifyAiCreateResp> response = restTemplate.exchange(url, HttpMethod.POST, entity, DifyAiCreateResp.class);

            // 判断请求是否成功
            if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
                String appId = response.getBody().getId();
                return ActionResult.success(appId);
            } else if (response.getStatusCode() == HttpStatus.UNAUTHORIZED) {
                // Token失效，尝试更新token后重试
                return handleTokenExpired(request, difyAiCreateReq, username, password);
            } else {
                return ActionResult.fail("创建Dify应用失败");
            }
        } catch (Exception e) {
            if (e.getMessage().contains("401")) {
                // Token失效，尝试更新token后重试
                return handleTokenExpired(request, difyAiCreateReq, username, password);
            }
            log.error("创建Dify应用异常", e);
            return ActionResult.fail("创建Dify应用异常: " + e.getMessage());
        }
    }

    private ActionResult handleTokenExpired(LoginReq request, DifyAiCreateReq difyAiCreateReq, String username, String password) throws Exception {
        // 重新登录获取新token
        LoginReq loginReq = new LoginReq();
        loginReq.setEmail(username);
        loginReq.setPassword(password);
        loginReq.setPlatform("1");
        ActionResult loginResult = this.apiLogin(loginReq);

        if (loginResult.getCode() != 200) {
            return ActionResult.fail("token失效且重新登录失败: " + loginResult.getMsg());
        }

        // 使用新token重新创建应用
        return this.createDifyAi(request, difyAiCreateReq);
    }


    private ActionResult handleLoginSuccess(String username, String password, String platform, String token) {
        ExternalLogin externalLogin = this.getByUsername(username);
        if (externalLogin == null) {
            externalLogin = new ExternalLogin();
            externalLogin.setId(RandomUtil.uuId());
        }
        externalLogin.setUsername(username);
        externalLogin.setPassword(password);

        // 直接使用传入的 token
        externalLogin.setToken(token);

        externalLogin.setPlatform(platform);
        externalLogin.setCreatedAt(new Date());
        this.saveOrUpdate(externalLogin);

        return ActionResult.success();
    }

    @Override
    public String getTokenByPlatform(String platform) throws Exception {
        String property = environment.getProperty("ragflow.api_refresh_token", "0");
        String username = "1".equals(platform) ? difyName : ragName;
        // 优化后的日志输出
        String platformName = "1".equals(property) ? "DIFY" : "RagFlow";
        log.info("{} 登录平台: {}, 用户名: {}", username, platformName, username);

        if ("0".equals(property)) {
            ExternalLogin login = lambdaQuery().eq(ExternalLogin::getUsername, username).eq(ExternalLogin::getPlatform, platform).one();
            if (login != null) {
                log.info("获取到的 token: {}", login.getToken());
            }
            return login != null ? login.getToken() : null;
        } else if ("1".equals(property)) {
            try {
                // 重新获取token
                LoginReq loginReq = new LoginReq();
                loginReq.setPlatform(platform);
                apiLogin(loginReq);
                ExternalLogin login = lambdaQuery().eq(ExternalLogin::getUsername, username).eq(ExternalLogin::getPlatform, loginReq.getPlatform()).one();
                if (login != null) {
                    log.info("重新获取到的 token: {}", login.getToken());
                }
                return login != null ? login.getToken() : null;
            } catch (Exception e) {
                log.error("重新获取token失败", e);
            }
        }
        return null;
    }
}
